package creation

import (
	"context"
	"fmt"
	v1alpha12 "gitverse.ru/synapse/kubelatte/pkg/api/v1alpha1"
	"gitverse.ru/synapse/kubelatte/pkg/observability/logs"
	"gitverse.ru/synapse/kubelatte/pkg/storage"
	"gitverse.ru/synapse/kubelatte/pkg/util"
	"gitverse.ru/synapse/kubelatte/pkg/util/templates"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	lbs "k8s.io/apimachinery/pkg/labels"
	"strings"
)

var RC *RenderController

type RenderController struct{}

func (r *RenderController) GetRenders(ctx context.Context, tiObject *v1alpha12.TriggerInstance) (renders []util.RenderItem) {
	triggers := storage.Storage.GetTriggers()
	templs := storage.Storage.GetTemplates()
	for _, trigger := range triggers {
		for _, config := range trigger.Spec.CreationConfigs {
			if r.CheckMatchSelector(ctx, &config, tiObject.Annotations, tiObject.Labels) {
				for _, ref := range config.TemplateRefs {
					t, ok := templs[ref]
					if ok {
						engine := templates.LoadTemplate(ctx, t)
						for _, engineTemplate := range engine.Templates() {
							var tempBuffer strings.Builder
							err := engineTemplate.Execute(&tempBuffer, tiObject)
							if err != nil {
								logs.Error(fmt.Sprintf("RenderController: getRenders failed %s", err))
								continue
							}
							renders = append(renders, util.RenderItem{
								Template:             t,
								Render:               tempBuffer.String(),
								Action:               config.Action,
								CreationIsUniqueName: config.DisableUniqueName != "true",
							})
							logs.Debug("Got render:", tempBuffer.String())
						}
					}
				}
			}
		}
	}
	return renders
}

func (r *RenderController) CheckMatchSelector(ctx context.Context, config *v1alpha12.CreationConfig, annotations map[string]string, labels map[string]string) bool {
	if labels != nil && len(config.LabelSelector.MatchExpressions) != 0 {
		labelSet := lbs.Set(labels)
		labelSelectors := metav1.LabelSelector{}

		for _, expression := range config.LabelSelector.MatchExpressions {

			labelSelectors.MatchExpressions = append(labelSelectors.MatchExpressions,
				metav1.LabelSelectorRequirement{
					Key:      expression.Key,
					Operator: expression.Operator,
					Values:   expression.Values,
				},
			)

			sel, err := metav1.LabelSelectorAsSelector(&labelSelectors)
			if err != nil {
				logs.Error(fmt.Sprintf("RenderController: checkMatchSelector failed %s", err))
			} else {
				return sel.Matches(labelSet)
			}
		}
	}

	if annotations != nil {
		triggerKey := fmt.Sprintf("%s/%s", config.AnnotationNamespace, config.AnnotationTrigger)
		triggerValue, ok := annotations[triggerKey]
		if ok {
			if triggerValue != "true" && triggerValue != "enabled" {
				logs.Error(fmt.Sprintf("RenderController: checkMatchSelector failed skip creation cause annotation value is not valid"))
			} else {
				return true
			}
		}
	}

	return false
}

func (r *RenderController) CheckTriggerTemplatePair(ctx context.Context) {
	triggers := storage.Storage.GetTriggers()
	templs := storage.Storage.GetTemplates()
	for _, trigger := range triggers {
		for _, config := range trigger.Spec.CreationConfigs {
			for _, ref := range config.TemplateRefs {
				_, ok := templs[ref]
				if !ok {
					logs.Error(fmt.Sprintf("RenderController: CheckTriggerTemplatePair Trigger[%s] contains invalid template ref %s", trigger.Name, ref))
				}
			}
		}
	}
}
